package com.medical.user.service.impl;

import com.medical.user.entity.User;
import com.medical.user.service.UserService;
import com.medical.user.util.JwtUtil;
import com.medical.user.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.exception.ConstraintViolationException;

import java.util.concurrent.ConcurrentHashMap;

/**
 * 用户服务实现类
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JwtUtil jwtUtil;

    // 用于记录登录失败次数
    private final ConcurrentHashMap<String, Integer> loginAttempts = new ConcurrentHashMap<>();
    private static final int MAX_LOGIN_ATTEMPTS = 5;

    @Override
    @Transactional
    public User register(User user) {
        log.info("开始注册用户: {}", user.getUsername());
        
        // 检查用户名是否已存在
        if (userRepository.findByUsername(user.getUsername()) != null) {
            log.warn("用户名已存在: {}", user.getUsername());
            throw new RuntimeException("用户名已存在");
        }

        // 检查邮箱是否已存在
        if (user.getEmail() != null && userRepository.findByEmail(user.getEmail()) != null) {
            log.warn("邮箱已存在: {}", user.getEmail());
            throw new RuntimeException("邮箱已被注册");
        }

        // 检查手机号是否已存在
        if (user.getPhone() != null && userRepository.findByPhone(user.getPhone()) != null) {
            log.warn("手机号已存在: {}", user.getPhone());
            throw new RuntimeException("手机号已被注册");
        }

        // 检查密码强度
        if (!isPasswordStrong(user.getPassword())) {
            log.warn("密码强度不符合要求: {}", user.getUsername());
            throw new RuntimeException("密码必须包含大小写字母和数字，长度至少6位");
        }

        // 加密密码
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        
        // 如果未指定角色，默认为患者角色
        if (user.getRole() == null) {
            user.setRole("ROLE_PATIENT");
        }

        // 验证角色值
        if (!isValidRole(user.getRole())) {
            log.warn("无效的角色值: {}", user.getRole());
            throw new RuntimeException("无效的角色值");
        }

        try {
            User savedUser = userRepository.save(user);
            log.info("用户注册成功: {}", user.getUsername());
            return savedUser;
        } catch (ConstraintViolationException e) {
            log.error("数据库约束冲突: {}", e.getMessage());
            if (e.getMessage().contains("email")) {
                throw new RuntimeException("邮箱已被注册");
            } else if (e.getMessage().contains("phone")) {
                throw new RuntimeException("手机号已被注册");
            } else if (e.getMessage().contains("username")) {
                throw new RuntimeException("用户名已存在");
            }
            throw new RuntimeException("注册失败: " + e.getMessage());
        } catch (Exception e) {
            log.error("用户注册失败: {}", user.getUsername(), e);
            throw new RuntimeException("用户注册失败: " + e.getMessage());
        }
    }

    @Override
    public String login(String username, String password) {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        // 检查用户状态
        if (user.getStatus() != 1) {
            throw new RuntimeException("账号已被禁用");
        }

        // 检查登录失败次数
        int attempts = loginAttempts.getOrDefault(username, 0);
        if (attempts >= MAX_LOGIN_ATTEMPTS) {
            throw new RuntimeException("登录失败次数过多，请稍后再试");
        }

        if (!passwordEncoder.matches(password, user.getPassword())) {
            // 增加失败次数
            loginAttempts.put(username, attempts + 1);
            throw new RuntimeException("密码错误");
        }

        // 登录成功，清除失败次数
        loginAttempts.remove(username);

        // 生成JWT token
        return jwtUtil.generateToken(username, user.getRole());
    }

    @Override
    @Transactional
    public User updateUser(User user) {
        User existingUser = userRepository.findById(user.getId())
                .orElseThrow(() -> new RuntimeException("用户不存在"));

        // 更新基本信息
        existingUser.setRealName(user.getRealName());
        existingUser.setPhone(user.getPhone());
        existingUser.setEmail(user.getEmail());

        return userRepository.save(existingUser);
    }

    @Override
    @Transactional
    public User updateUserRole(Long userId, String role) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在"));

        // 验证角色值
        if (!isValidRole(role)) {
            throw new RuntimeException("无效的角色值");
        }

        user.setRole(role);
        return userRepository.save(user);
    }

    @Override
    public User findByUsername(String username) {
        return userRepository.findByUsername(username);
    }

    private boolean isPasswordStrong(String password) {
        if (password == null || password.length() < 6) {
            log.warn("密码长度不足6位");
            return false;
        }
        boolean hasUpperCase = false;
        boolean hasLowerCase = false;
        boolean hasDigit = false;
        
        for (char c : password.toCharArray()) {
            if (Character.isUpperCase(c)) hasUpperCase = true;
            if (Character.isLowerCase(c)) hasLowerCase = true;
            if (Character.isDigit(c)) hasDigit = true;
        }
        
        if (!hasUpperCase) log.warn("密码缺少大写字母");
        if (!hasLowerCase) log.warn("密码缺少小写字母");
        if (!hasDigit) log.warn("密码缺少数字");
        
        return hasUpperCase && hasLowerCase && hasDigit;
    }

    private boolean isValidRole(String role) {
        boolean isValid = role != null && (
            role.equals("ROLE_PATIENT") ||
            role.equals("ROLE_DOCTOR") ||
            role.equals("ROLE_ADMIN")
        );
        if (!isValid) {
            log.warn("无效的角色值: {}", role);
        }
        return isValid;
    }
} 